/* 
    Forked from JSPWiki - a JSP-based WikiWiki clone.

    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.  
 */
package jspwiki.plugins;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.ecyrd.jspwiki.TextUtil;
import com.ecyrd.jspwiki.WikiContext;
import com.ecyrd.jspwiki.WikiEngine;
import com.ecyrd.jspwiki.WikiPage;
import com.ecyrd.jspwiki.auth.AuthorizationManager;
import com.ecyrd.jspwiki.auth.permissions.PermissionFactory;
import com.ecyrd.jspwiki.plugin.PluginException;
import com.ecyrd.jspwiki.plugin.WikiPlugin;
import com.ecyrd.jspwiki.providers.ProviderException;

/**
 * Forked from JSPWiki core InsertPage plugin. Removed class, style, maxLength
 * params. Added mode param as per InsertPage tag. Recursive HTML inserts would
 * be dumbed down to PLAIN.
 * 
 * @since 2.1.37
 * @author Scott Hurlbert
 * 
 * @author Francis Novilla
 */
public class InsertPage implements WikiPlugin {

  public static final String PARAM_PAGENAME = "page";
  public static final String PARAM_SECTION = "section";
  public static final String PARAM_MODE = "mode";

  public enum Mode {
    HTML, PLAIN, RAW
  };

  /**
   * This attribute is stashed in the WikiContext to make sure that we don't
   * have circular references.
   */
  public static final String ATTR_RECURSE = InsertPage.class.getName() + ".recurse";

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public String execute(WikiContext context, Map params) throws PluginException {
    WikiEngine engine = context.getEngine();

    StringBuffer res = new StringBuffer();

    String includedPage = (String) params.get(PARAM_PAGENAME);
    int section = TextUtil.parseIntParameter((String) params.get(PARAM_SECTION), -1);
    Mode mode = Mode.valueOf((String) params.get(PARAM_MODE));

    if (includedPage != null) {
      includedPage = context.getPage().getName();
    }

    WikiPage page = null;
    try {
      String pageName = engine.getFinalPageName(includedPage);
      if (pageName != null) {
        page = engine.getPage(pageName);
      } else {
        page = engine.getPage(includedPage);
      }
    } catch (ProviderException e) {
      res.append("<span class=\"error\">Page could not be found by the page provider.</span>");
      return res.toString();
    }

    // Check for recursivity
    List<String> previousIncludes = (List) context.getVariable(ATTR_RECURSE);

    if (previousIncludes != null) {
      if (previousIncludes.contains(page.getName()) && mode == Mode.HTML) {
        mode = Mode.PLAIN;
      }
    } else {
      previousIncludes = new ArrayList<String>();
    }

    previousIncludes.add(page.getName());
    context.setVariable(ATTR_RECURSE, previousIncludes);

    // Check for permissions
    AuthorizationManager mgr = engine.getAuthorizationManager();

    if (!mgr.checkPermission(context.getWikiSession(), PermissionFactory.getPagePermission(page, "view"))) {
      res.append("<span class=\"error\">You do not have permission to view this included page.</span>");
      return res.toString();
    }

    /**
     * We want inclusion to occur within the context of its own page, because we
     * need the links to be correct.
     */

    WikiContext includedContext = (WikiContext) context.clone();
    includedContext.setPage(page);

    switch (mode) {
    case HTML:
      res.append(engine.textToHTML(includedContext, extractSection(section, engine.getPureText(page))));
      break;
    case PLAIN:
      res.append(extractSection(section, engine.getText(includedContext, page)));
      break;
    case RAW:
      res.append(extractSection(section, engine.getPureText(page)));
      break;
    }

    // Remove the name from the stack; we're now done with this.
    previousIncludes.remove(page.getName());
    context.setVariable(ATTR_RECURSE, previousIncludes);

    return res.toString();
  }

  private String extractSection(int section, String pageData) throws PluginException {
    if (section != -1) {
      try {
        pageData = TextUtil.getSection(pageData, section);
      } catch (IllegalArgumentException e) {
        throw new PluginException(e.getMessage());
      }
    }
    return pageData;
  }

}
